package cn.virens.web.components.shiro.simple;

import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.credential.CredentialsMatcher;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.cache.CacheManager;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.SimplePrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;

import cn.virens.web.components.shiro.ShiroAuthInterface;
import cn.virens.web.components.shiro.ShiroRealmInterface;
import cn.virens.web.components.shiro.token.ChannelResult;
import cn.virens.web.components.shiro.token.ChannelToken;

/**
 * 用户身份识别/权限校验
 * 
 * @author virens
 */
public class SimpleAuthorizingRealm extends AuthorizingRealm implements ShiroRealmInterface {
	@Autowired
	@Qualifier(ShiroAuthInterface.SHIRO_BEAN_NAME)
	private ShiroAuthInterface shiroAuthInterface;

	public SimpleAuthorizingRealm() {
		this(new HashedCredentialsMatcher("MD5"));
	}

	public SimpleAuthorizingRealm(CacheManager manager) {
		this(manager, null);
	}

	public SimpleAuthorizingRealm(CredentialsMatcher matcher) {
		this(null, matcher);
	}

	public SimpleAuthorizingRealm(CacheManager manager, CredentialsMatcher matcher) {
		super(manager, matcher);
	}

	@Override
	public void clearAuthorizationInfo(String principal) {
		this.clearCachedAuthorizationInfo(new SimplePrincipalCollection(principal, getName()));
	}

	@Override
	public void clearAuthenticationInfo(String principal) {
		this.clearCachedAuthenticationInfo(new SimplePrincipalCollection(principal, getName()));
	}

	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
		Object principal = getAvailablePrincipal(principals);
		SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();

		authorizationInfo.addRoles(shiroAuthInterface.getRoles(principal));// 获取用户角色列表
		authorizationInfo.addStringPermissions(shiroAuthInterface.getResources(principal)); // 获取用户权限列表

		return authorizationInfo;
	}

	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
		if (!(token instanceof ChannelToken)) throw new UnknownAccountException();

		// 根据登录信息查询用户信息
		ChannelResult result = shiroAuthInterface.getUserToken((ChannelToken) token);
		if (!ChannelResult.vaild(result)) throw new UnknownAccountException("用户不存在");

		// 返回认证信息
		return new SimpleAuthenticationInfo(result.getUuid(), result.getPassword(), getName());
	}

	@Override
	protected Object getAuthenticationCacheKey(AuthenticationToken token) {
		return token("shrio:authentication:", token);
	}

	@Override
	protected Object getAuthenticationCacheKey(PrincipalCollection principals) {
		return object("shrio:authentication:", super.getAvailablePrincipal(principals));
	}

	@Override
	protected Object getAuthorizationCacheKey(PrincipalCollection principals) {
		return object("shrio:authorization:", super.getAvailablePrincipal(principals));
	}

	private String token(String pref, AuthenticationToken token) {
		return (token == null ? null : (pref + token.getPrincipal()));
	}

	private String object(String pref, Object obj) {
		return (obj == null ? null : (pref + obj.toString()));
	}
}
